package framework.model;

import framework.controller.AddCompanyAccountController;
import framework.controller.AddPersonalAccountController;
import framework.controller.IController;
import framework.controller.ITransaction;
import framework.controller.Deposit;
import framework.controller.DepositController;
import framework.controller.Withdraw;
import framework.controller.WithdrawController;
import framework.view.AccountTableModel;
import framework.view.AddCompanyAccountDialog;
import framework.view.AddPersonalAccountDialog;
import framework.view.OperationPanel;
import framework.view.TablePanel;
import framework.view.TopPanel;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import javax.swing.table.AbstractTableModel;

public class Factory implements IFactory {

    private static Factory instance;
    private FinancialCompany financialCompany;

    public void setFinancialCompany(FinancialCompany financialCompany) {
        this.financialCompany = financialCompany;
    }

    public FinancialCompany getFinancialCompany() {
        return financialCompany;
    }

    public static void setFactory(Factory f) {
        instance = f;
    }

    public static Factory getInstance() {
        if (instance == null) {
            instance = new Factory();
        }
        return instance;
    }

    public IController createAddPersonalAccountController() {
        return new AddPersonalAccountController();
    }

    public IController createAddCompanyAccountController() {
        return new AddCompanyAccountController();
    }

    public Entry createEntry(double amount) {
        return new Entry(amount);
    }

    public ITransaction createTransaction(Account acc, Entry ent, int type) {
        switch (type) {
            case ITransaction.T_DEPOSIT:
                return new Deposit(acc, ent);
            case ITransaction.T_WITHDRAW:
                return new Withdraw(acc, ent);
            default:
                return null;
        }
    }

    public Address createAddress(String street, String city, String state, String zip) {
        return new Address(street, city, state, zip);
    }

    public Customer createCustomer(HashMap<String, String> fields) {
        Address addr = createAddress(fields.get(Constant.A_STREET), fields.get(Constant.A_CITY),
                fields.get(Constant.A_STATE), fields.get(Constant.A_ZIP));
        System.out.println("New Customer is created: " + fields.get(Constant.A_NAME));
        // recognize account type by field "customer_type"
        if (Constant.CTYPE_COMPANY.equals(fields.get(Constant.A_ACCOUNT_TYPE))) {
            return new Organization(fields.get(Constant.A_NAME), fields.get(Constant.A_EMAIL), addr, fields.get(Constant.A_NO_OF_EMPLOYEE));
        } else {
            return new Person(fields.get(Constant.A_NAME), fields.get(Constant.A_EMAIL), addr, fields.get(Constant.A_BIRTHDAY));
        }
    }

    public Account createAccount(Customer cust, HashMap<String, String> fields) {
        return new DefaultAccount(cust);
    }

    public IFunctor createFunctor(int type) {
        switch (type) {
            case IFunctor.T_SUM: // default                
            default:
                return new SumFunctor();
        }        
    }

    public IController createDepositController() {
        return new DepositController("Deposit");
    }

    public IController createWithdrawController() {
        return new WithdrawController("Withdraw");
    }

    public AbstractTableModel createAccountTableModel() {
        return new AccountTableModel();
    }

    public TopPanel createTopPanel() {
        return new TopPanel();
    }

    public OperationPanel createOperationPanel() {
        return new OperationPanel("Deposit", "Withdraw");
    }

    public TablePanel createTablePanel() {
        return new TablePanel();
    }

    public AddPersonalAccountDialog createAddPersonalAccountDialog() {
        return new AddPersonalAccountDialog();
    }

    public AddCompanyAccountDialog createAddCompanyAccountDialog() {
        return new AddCompanyAccountDialog();
    }
    
    public IPredicate createPredicate(int type) {
        switch (type) {
            case IPredicate.T_MONTHLY: 
                Date d = Calendar.getInstance().getTime();
                return new  MonthlyPredicate(d.getMonth() - 1);
            case IPredicate.T_DEPOSIT:      
                return new DepositPredicate();
            case IPredicate.T_WITHDRAW:      
                return new WithdrawPredicate();
            default:
                return null;
        }
    }
    
    public IController createController(int type) {
        switch (type) {          
            case IController.T_DEPOSIT:      
                return new DepositController("Deposit");
            case IController.T_WITHDRAW:      
                return new WithdrawController("Withdraw");
            case IController.T_CHARGE:                 
                return new WithdrawController("Charge");                  
            default:
                return null;
        }
    }    
}
